﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net.Sockets;

namespace SGSGameServer.Protocal
{
    public class NetMessage : NetMessage<string>
    {
        public NetMessage()
            : base()
        {
        }

        public NetMessage( string content )
            : base( content )
        {
        }
    }

    public class NetMessage<T>
    {
        public NetMessage()
        {
        }

        public NetMessage( T contentObject )
        {
            ContentObject = contentObject;
            ContentMessage = SGS.Utility.XmlSerializerHelper.Serialize( contentObject );
            this.Size = Encoding.UTF8.GetByteCount( ContentMessage );
        }

        public int Size
        {
            get;
            set;
        }

        public T ContentObject
        {
            get;
            set;
        }

        public string ContentMessage
        {
            get;
            set;
        }

        public static NetMessage<T> FromByte( byte[] data )
        {
            NetMessage<T> msg = null;
            try
            {
                msg = new NetMessage<T>();

                using (MemoryStream ms = new MemoryStream( data ))
                {
                    using (StreamReader sr = new StreamReader( ms ))
                    {
                        byte[] buffer = new byte[4];
                        if (ms.Read( buffer, 0, buffer.Length ) == 0)
                        {
                            throw new Exception( "data is empty" );
                            // error
                        }
                        else
                        {
                            // read length ok
                            msg.Size = BitConverter.ToInt32( buffer, 0 );
                            buffer = new byte[msg.Size];
                            ms.Read( buffer, 0, buffer.Length );

                            msg.ContentMessage = Encoding.UTF8.GetString( buffer );
                            msg.ContentObject = SGS.Utility.XmlSerializerHelper.Deserialize<T>( msg.ContentMessage );
                        }
                    }
                }
            }
            catch
            {
                throw;
            }
            return msg;
        }

        //public static NetMessage<T> FromAndReduceByte( byte[] data )
        //{
        //    NetMessage msg = null;
        //    try
        //    {
        //        msg = new NetMessage();

        //        using (MemoryStream ms = new MemoryStream( data ))
        //        {
        //            using (StreamReader sr = new StreamReader( ms ))
        //            {
        //                byte[] buffer = new byte[4];
        //                if (ms.Read( buffer, 0, buffer.Length ) == 0)
        //                {
        //                    throw new Exception( "data is empty" );
        //                    // error
        //                }
        //                else
        //                {
        //                    // read length ok
        //                    msg.Size = BitConverter.ToInt32( buffer, 0 );
        //                    buffer = new byte[msg.Size];
        //                    ms.Read( buffer, 0, buffer.Length );

        //                    msg.Content = Encoding.UTF8.GetString( buffer );
        //                }
        //            }
        //        }

        //        Buffer.BlockCopy( data, 4 + msg.Size, data, 0, data.Length - 4 - msg.Size );
        //    }
        //    catch
        //    {
        //        throw;
        //    }
        //    return msg;
        //}

        public static NetMessage<T> FromNetworkStream( NetworkStream ns )
        {
            NetMessage<T> msg = new NetMessage<T>();
            byte[] buffer = new byte[4];
            int readcount;

            readcount = ns.Read( buffer, 0, buffer.Length );
            Console.WriteLine( readcount );
            if (readcount == 0)
            {
                throw new Exception( "socket data error : 1" );
            }

            msg.Size = BitConverter.ToInt32( buffer, 0 );
            // buffer = new byte[msg.Size];

            buffer = new byte[1024];

            var bufferAllData = new byte[msg.Size];
            int readAllCount = 0;
            readcount = 0;

            try
            {
                while (readAllCount < msg.Size)
                {
                    if (msg.Size - readAllCount < buffer.Length)
                    {
                        readcount = ns.Read( buffer, 0, msg.Size - readAllCount );
                    }
                    else
                    {
                        readcount = ns.Read( buffer, 0, buffer.Length );
                    }

                    Buffer.BlockCopy( buffer, 0, bufferAllData, readAllCount, readcount );
                    readAllCount += readcount;
                }
            }
            catch
            {
                Console.WriteLine( readAllCount );
                // Console.WriteLine( bufferAllData[readAllCount] );
                Console.WriteLine( readcount );
            }

            // Console.WriteLine(readcount);
            if (readcount == 0)
            {
                throw new Exception( "socket data error : 1" );
            }
            msg.ContentMessage = Encoding.UTF8.GetString( bufferAllData );
            msg.ContentObject = SGS.Utility.XmlSerializerHelper.Deserialize<T>( msg.ContentMessage );

            return msg;
        }

        public static NetMessage<T> FromSocket(Socket socket)
        {
            NetMessage<T> msg = new NetMessage<T>();
            byte[] buffer = new byte[4];
            int readcount;

            readcount = socket.Receive(buffer, 4, SocketFlags.None);

            // readcount = ns.Read(buffer, 0, buffer.Length);
            // Console.WriteLine(readcount);
            if (readcount < 0)
            {
                throw new Exception("socket data error : 1");
            }

            msg.Size = BitConverter.ToInt32(buffer, 0);
            // buffer = new byte[msg.Size];

            buffer = new byte[1024];

            var bufferAllData = new byte[msg.Size];
            int readAllCount = 0;
            readcount = 0;

            try
            {
                while (readAllCount < msg.Size)
                {
                    if (msg.Size - readAllCount < buffer.Length)
                    {
                        readcount = socket.Receive(buffer, 0, msg.Size - readAllCount, SocketFlags.None);
                    }
                    else
                    {
                        readcount = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
                    }

                    Buffer.BlockCopy(buffer, 0, bufferAllData, readAllCount, readcount);
                    readAllCount += readcount;
                }
            }
            catch
            {
                throw;
                // Console.WriteLine(readAllCount);
                // Console.WriteLine( bufferAllData[readAllCount] );
                // Console.WriteLine(readcount);
            }

            // Console.WriteLine(readcount);
            if (readcount == 0)
            {
                throw new Exception("socket data error : 1");
            }
            msg.ContentMessage = Encoding.UTF8.GetString(bufferAllData);
            msg.ContentObject = SGS.Utility.XmlSerializerHelper.Deserialize<T>( msg.ContentMessage );

            return msg;
        }

        public byte[] ToBytes()
        {
            using (MemoryStream ms = new MemoryStream())
            {
                byte[] buffer;
                buffer = BitConverter.GetBytes( this.Size );
                ms.Write( buffer, 0, buffer.Length );
                buffer = Encoding.UTF8.GetBytes( ContentMessage );
                ms.Write( buffer, 0, buffer.Length );

                return ms.ToArray();
            }
        }
        
        
    }
}
